import type { IsEqual, EmptyObject } from 'type-fest';

// # 调用签名：可调用 (并且不可被 implement)
type CallSign = (x: number, y: number) => number;
type CallSign2 = { (x: number, y: number): number };
declare const add: CallSign;

// 构造签名：调用时需要使用 new 关键字创建对象 (同样不可 implement)
{
  class Person {
    constructor(name: string, age: number) {}
  }
  type ReCtor<T> = T extends {
    new (...args: infer U): infer V;
    prototype: infer W;
  }
    ? { new (...args: U): V; prototype: W }
    : never;
  type Class<T, Arguments extends unknown[] = any[]> = {
    prototype: Pick<T, keyof T>;
    new (...arguments_: Arguments): T;
  };
  type ClassPerson = Class<PersonImpl, Arg>;
  type Arg = ConstructorParameters<typeof Person>;
  type PersonImpl = InstanceType<typeof Person>;
  type PersonConstructor = { new (...arg: Arg): Person };
  //                   ^?
  type _ = IsEqual<ReCtor<typeof Person>, ClassPerson>;
  //   ^?
  class NewPerson implements Person {
    constructor(name: string, age: number) {
      return new Person(name, age);
    }
  }
}
const __a = {
  get name() {
    return 'name';
  },
};

// # 重载签名：有多个签名的 函数 (_对象)
type OverrideSign = {
  (x: number, y: number, z: number): number;
  (x: number, y: number): number;
  (x: number, y: number, z?: number): number;
};
type OverrideSignIntersection = ((x: number, y: number, z: number) => number) &
  ((x: number, y: number) => number) &
  ((x: number, y: number, z?: number) => number);

// # 实现签名：单指重载签名的 function body
let add2: OverrideSign | undefined = undefined;

type OverrideEq = IsEqual<OverrideSign, OverrideSignIntersection>;
//      ^?

// { /// *** DOM-Only *** ///
//   // case: createHTML
//   type CreateHTML<
//     T extends keyof HTMLElementTagNameMap = keyof HTMLElementTagNameMap,
//   > = {
//     <K extends T = T>(tag: K extends T ? K : never): HTMLElementTagNameMap[K];
//     (tag: string): HTMLUnknownElement;
//   };
//   type CreateDataElement = CreateHTML<'data'>;

//   let a!: CreateDataElement;

//   const b = a('data');
// }
// 多态，泛型参数
{
  let names = [
    { firstName: 'beth' },
    { firstName: 'jane' },
    { firstName: 'john' },
  ];
  type Filter = {
    // (array: string[], f: (item: string) => boolean): string[];
    <T>(array: T[], f: (item: T) => boolean): T[];
  };
  const filter: Filter = (array: any[], f: any) => {
    let result = [];
    for (let i = 0; i < array.length; i++) {
      let item = array[i];
      if (f(item)) {
        result.push(item);
      }
    }
    return result;
  };
  let result = filter(names, (_) => _.firstName.startsWith('j'));

  function map<T, U>(array: T[], f: (items: T) => U): U[] {
    let result = [];
    for (let i = 0; i < array.length; i++) {
      let item = array[i];
      result.push(f(item));
    }
    return result;
  }
  map(['a', 'b', 'c'], (_) => _.toUpperCase());

  let p = new Promise<number>((resolve) => resolve(1));

  type TreeNode = { value: string };
  type LeafNode = TreeNode & { isLeaf: true };
  type InnerNode = TreeNode & { children: TreeNode[] };

  function mapNode<T extends TreeNode>(
    node: T,
    f: (node: string) => string,
  ): T {
    return {
      ...node,
      value: f(node.value),
    };
  }
  let tn!: TreeNode;
  const tnc = mapNode(tn, (_) => _);
  //     ^?
  let ln!: LeafNode;
  const lnc = mapNode(ln, (_) => _);
  //     ^?
  let in_!: InnerNode;
  const inc = mapNode(in_, (_) => _);
  //     ^?
}

{
  type _UV = never extends unknown ? 1 : 0;
  type _U<T> = {} extends { name: string } ? 1 : 0;

  type _CU = _U<unknown>;

  type falsy = 0 | '' | 0n | null | undefined;

  // @ts-expect-error - no typeLiteral Infinity
  const _a = Infinity as const;
  //    ^?

  // @ts-expect-error - no typeLiteral NaN
  const _b = NaN as const;
  //     ^?
}
// 有默认参数的 arguments 会很坑：只能获取实际传入的参数数量
function a(x = 1, y = 2) {
  console.log(arguments);
}
